#include"Task.hpp"
#include<string>
#include<vector>
#include<cstdlib>
#include<ctime>
#include<cassert>
#include<unistd.h>
#include<sys/stat.h>
#include<sys/wait.h>

const int processnum=10;
vector<task_t> tasks;

//先描述
class channel
{
public:
    channel(int cmdfd,int slaverid,string &processname)
    :_cmdfd(cmdfd),
    _slaverid(slaverid),
    _processname(processname)
    {}
public:
    int _cmdfd;         //发送任务的文件描述符
    pid_t _slaverid;    //子进程的pid
    string _processname;//子进程的名字-方便打印日志
};

void slaver()
{
    while(true)
    {
        int cmdcode=0;
        int n=read(0,&cmdcode,sizeof(int));//如果父进程不给子进程发数据就阻塞等待
        if(n==sizeof(int))
        {
            //执行cmdcode对应的任务列表
            cout<<"slaver say@ get a command: "<<getpid()<<" cmdcode: "<<cmdcode<<endl;
            if(cmdcode>=0&&cmdcode<tasks.size()) tasks[cmdcode](); 
        }
        if(n==0) break;
    }
}
 void InitProcessPool(vector<channel> *channels)
{
    vector<int> oldfds;//确保每个子进程只有一个写端
    for(int i=0;i<processnum;i++)
    {
        int pipefd[2];//临时空间
        int n=pipe(pipefd);
        assert(!n);//演示检查管道打开失败,注意只能在debug版本中使用
        (void)n;//显式处理未使用变量 n 以避免编译警告。

        pid_t id=fork();
        if(id==0){
            //子进程
            cout<<"child: "<<getpid()<<" close history fd: ";
            for(auto fd:oldfds){
                cout<<fd<<" ";
            }
            cout<<"\n";

            close(pipefd[1]);//关闭不使用的端口
            dup2(pipefd[0],0);//进行重定向，目的是不用从管道中读取数据直接从标准输入中读
            close(pipefd[0]);
            slaver();//子进程执行命令操作
            std::cout << "process : " << getpid() << " quit" <<endl;//执行完后退出语句
            exit(0);
        }
        //父进程
        close(pipefd[0]);//关闭不用的端
        oldfds.push_back(pipefd[1]);//添加继承下去的写端
        //容器中添加新的channel
        string name= "process-" + to_string(i);
        channels->push_back(channel(pipefd[1],id,name));
        sleep(1);
    }
}

void Debug(const vector<channel> &channels)
{
    for(auto c:channels)
    {
        cout<<c._cmdfd<<" "<<c._slaverid<<" "<<c._processname<<endl;
    }
}

void menu()
{
    cout<<"###################"<<endl;
    cout<<"#1.刷新屏幕使用时长#"<<endl;
    cout<<"#2.输出内存使用情况#"<<endl;
    cout<<"#3.检查更新状态    #"<<endl;
    cout<<"#4.更新错误日志    #"<<endl;
    cout<<"#0.退出           #"<<endl;
    cout<<"###################"<<endl;
}

void CtrlSlaver(const vector<channel> &channels)
{
    int which=0;//用于选择哪一个子进程
    while(true)
    {
        int select=0;//选择哪一个任务
        menu();
        cout<<"please enter@"<<endl;
        cin>>select;
        if(select<=0||select>4) break;
        //1.选择任务
        int cmdcode=select-1;//tasks中作为数组下标要-1
        //2.选择进程
        cout<<" father say: "<<" cmdcode: "<<cmdcode<<" already send to "
        <<channels[which]._processname<<endl;
        //3.发送任务
        //传函数指针地址再进程间通信无意义，别的进程无法访问自身内存
        //write(channels[which]._cmdfd,&tasks[cmdcode],sizeof(tasks[cmdcode]));
        write(channels[which]._cmdfd,&cmdcode,sizeof(cmdcode));
        which++;
        which%=channels.size();
    }
}

void QuitProcess(const vector<channel> &channels)
{
    //情况1：
    // for(int i=channels.size()-1;i>=0;i--) 
    // {
    //     close(channels[i]._cmdfd);
    //     waitpid(channels[i]._slaverid,nullptr,0);
    // }

    //情况2：
    for(const auto &c : channels) close(c._cmdfd);
    for(const auto &c : channels) waitpid(c._slaverid, nullptr, 0);
}
int main()
{
    LoadTask(&tasks);//加载任务列表
    srand(time(nullptr)^getpid()^1023);//种一个随机数种子,高随机性
    //再组织
    vector<channel> channels;//将子进程用容器管理起来

    //1.初始化
    InitProcessPool(&channels);
    //Debug(channels);
    //2.开始控制子进程
    CtrlSlaver(channels);
    //3.清理收尾
    QuitProcess(channels);
    return 0;
}